极客实验室是极客国际公园旗下为未来而构建的极客社区;
我们正在构建一个活跃的小众社区,汇聚众多优秀开发者与设计师;
关注极具创新精神的前沿技术&分享交流&项目合作机会等互联网行业服务;
Open开放 · Creation创想 | OpenSource开放成就梦想 GeekParkHub共建前所未见!
Future Vision : Establishment of the Geek Foundation;
GeekParkHub GithubHome:https://github.com/geekparkhub
GeekParkHub GiteeHome:https://gitee.com/geekparkhub
欢迎贡献各领域开源野生Blog&笔记&文章&片段&分享&创想&OpenSource Project&Code&Code Review
🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈 issues: geekparkhub.github.io/issues 🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈
Apache ZooKeeper是Apache软件基金会的一个软件项目,他为大型分布式计算提供开源的分布式配置服务、同步服务和命名注册,ZooKeeper曾经是Hadoop的一个子项目,但现在是一个独立的顶级项目。
ZooKeeper的架构通过冗余服务实现高可用性,因此,如果第一次无应答,客户端就可以询问另一台ZooKeeper主机,ZooKeeper节点将它们的数据存储于一个分层的命名空间,非常类似于一个文件系统或一个前缀树结构,客户端可以在节点读写,从而以这种方式拥有一个共享的配置服务,更新是全序的. —— 维基百科
zookeeper从设计模式角度来理解,是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理数据,然后接受观察者注册,一旦这些数据状态发送变化,zookeeper就将负责通知已经在zookeeper上注册的那些观察者做出相应反应
1.zookeeper一个
领导者 leader,多个跟随者 follower组成集群
2.集群中只要有半数以上节点存活,zookeeper集群就能正常服务
3.全局数据一致,每个server保存一份相同的数据备份,Client无论连接哪一个服务,数据都是一致的
4.更新请求顺序执行,来自同一个客户端的更新请求按其发送顺序依次执行
5.数据更新原子性,一次数据更新要么成功要么失败
6.实时性,在一定时间范围内,客户端能读到最新数据
zookeeper数据模型与Unix文件系统很相似,整体上可以看作是一棵树,每个节点称作一个znode,每个zonde默认能够储存1MB数据,每个znode都可以通过其路径唯一标识
提供服务包括:
统一命名服务,统一配置管理,统一集群管理,服务节点动态上下线,软负载均衡统一命名服务:在分布式环境下,经常需要对应用/服务进行统一命名,便于识别.
统一配置管理:分布式环境下,配置文件同步,一般要求一个集群中,所有节点配置信息是一致的,对配置文件修改后,希望能够快速同步到各个节点上,配置管理可交由zookeeper实现,可将配置信息写入zookeeper上znode节点,各个客户端服务器监听此znode,一旦znode中数据被修改,zookeeper将通知各个客户端服务器.
统一集群管理:在分布式环境中,实现掌握每个节点的状态,可根据节点实时状态做出一些调整,zookeeper可以实现实时监控节点状态变化,可以将节点信息写入zookeeper上一个znode,监听znode可以获取实时状态变化.
软负载均衡:在zookeeper中记录每台服务器的访问数,让王文数量少的服务器去处理最新客户端请求.
Zookeeper Download Address: archive.apache.org/dist/zookeeper
1.[geek-developer@servicehub opt]$ ll
2.total 408816
3.-rw-r--r--. 1 root root 35042811 Jan 17 00:00 zookeeper-3.4.10.tar.gz
1.#解压zookeeper.tar.gz
2.tar -zxvf zookeeper-3.4.10.tar.gz
1.#将zookeeper-3.4.10重命名为zookeeper
2.mv zookeeper-3.4.10 zookeeper
1.#cd指令进入到/opt/zookeeper/目录下
2.[geek-developer@servicehub opt]$ cd /opt/zookeeper/
3.# 列表查看当前目录下文件
4.[geek-developer@servicehub zookeeper]$ ll
5.total 2752
6.drwxr-xr-x. 2 1001 1001 4096 Mar 23 2017 bin
7.-rw-rw-r--. 1 1001 1001 84725 Mar 23 2017 build.xml
8.drwxr-xr-x. 2 1001 1001 4096 Jan 19 18:11 conf
9.drwxr-xr-x. 10 1001 1001 4096 Mar 23 2017 contrib
10.drwxr-xr-x. 2 1001 1001 4096 Mar 23 2017 dist-maven
11.drwxr-xr-x. 6 1001 1001 4096 Mar 23 2017 docs
12.-rw-rw-r--. 1 1001 1001 1709 Mar 23 2017 ivysettings.xml
13.-rw-rw-r--. 1 1001 1001 5691 Mar 23 2017 ivy.xml
14.drwxr-xr-x. 4 1001 1001 4096 Mar 23 2017 lib
15.-rw-rw-r--. 1 1001 1001 11938 Mar 23 2017 LICENSE.txt
16.-rw-rw-r--. 1 1001 1001 3132 Mar 23 2017 NOTICE.txt
17.-rw-rw-r--. 1 1001 1001 1770 Mar 23 2017 README_packaging.txt
18.-rw-rw-r--. 1 1001 1001 1585 Mar 23 2017 README.txt
19.drwxr-xr-x. 5 1001 1001 4096 Mar 23 2017 recipes
20.drwxr-xr-x. 8 1001 1001 4096 Mar 23 2017 src
21.-rw-rw-r--. 1 1001 1001 1456729 Mar 23 2017 zookeeper-3.4.10.jar
22.-rw-rw-r--. 1 1001 1001 819 Mar 23 2017 zookeeper-3.4.10.jar.asc
23.-rw-rw-r--. 1 1001 1001 33 Mar 23 2017 zookeeper-3.4.10.jar.md5
24.-rw-rw-r--. 1 1001 1001 41 Mar 23 2017 zookeeper-3.4.10.jar.sha1
25.-rw-r--r--. 1 root root 1183464 Jan 20 02:06 zookeeper.out
26.[geek-developer@servicehub zookeeper]$
1.#在此目录创建zkData文件夹,可以根据官方说明创建或自定义文件夹名称
2.mkdir zkData
1.#cd指令进入到/opt/zookeeper/conf目录下
2.[geek-developer@servicehub opt]$ cd /opt/zookeeper/conf
3.# 列表查看当前目录下文件
4.[geek-developer@servicehub conf]$ ll
5.total 12
6.-rw-rw-r--. 1 1001 1001 535 Mar 23 2017 configuration.xsl
7.-rw-rw-r--. 1 1001 1001 2161 Mar 23 2017 log4j.properties
8.-rw-rw-r--. 1 1001 1001 1053 Jan 19 00:00 zoo_sample.cfg
9.[geek-developer@servicehub conf]$
1.#将zoo_sample.cfg文件重命名为zoo.cfg
2.mv zoo_sample.cfg zoo.cfg
1.#切换管理员身份
2.[geek-developer@corehub ~]$ su - root
3.#输入密码 注意:密码隐藏不可见,输入正确回车即可
4.Password:
5.#cd指令进入到/opt/zookeeper/conf目录下
6.[root@corehub ~]# cd /opt/devtool/zookeeper/conf
7.# 列表查看当前目录下文件
8.[root@corehub-001 conf]# ll
9.total 12
10.-rw-rw-r--. 1 1001 1001 535 Mar 23 2017 configuration.xsl
11.-rw-rw-r--. 1 1001 1001 2161 Mar 23 2017 log4j.properties
12.-rw-rw-r--. 1 1001 1001 1055 Jan 18 19:41 zoo.cfg
13.#vim编辑zoo.cfg文件
14.[root@corehub conf]# vim zoo.cfg
1.#按住i键进入编辑模式 找到名称为dataDir并修改配置
2.# The number of milliseconds of each tick
3.tickTime=2000
4.# The number of ticks that the initial
5.# synchronization phase can take
6.initLimit=10
7.# The number of ticks that can pass between
8.# sending a request and getting an acknowledgement
9.syncLimit=5
10.# the directory where the snapshot is stored.
11.# do not use /tmp for storage, /tmp here is just
12.# example sakes.
13.############需要修改当前数据存放位置#############
14.###编辑完毕,按Esc键,返回并输入:wq写入并退出vim模式###
15.dataDir=/opt/devtool/zookeeper/zkData
16.# the port at which the clients will connect
17.clientPort=2181
18.# the maximum number of client connections.
19.# increase this if you need to handle more clients
20.#maxClientCnxns=60
21.#
22.# Be sure to read the maintenance section of the
23.# administrator guide before turning on autopurge.
24.#
25.# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
26.#
27.# The number of snapshots to retain in dataDir
28.#autopurge.snapRetainCount=3
29.# Purge task interval in hours
30.# Set to "0" to disable auto purge feature
31.#autopurge.purgeInterval=1
1.#返回上一层目录
2.[root@corehub conf]# cd ..
3.#在bin目录下执行zkServer.sh脚本
4.[root@corehub zookeeper]# bin/zkServer.sh start
1.#在bin目录下执行zkCli.sh脚本
2.[root@corehub zookeeper]# bin/zkCli.sh
1.#在bin目录下执行zkServer.sh脚本
2.[root@corehub zookeeper]# bin/zkServer.sh stop
1.quit
1.1.tickTime=2000 : 通信心跳数,zookeeper服务端与客户端心跳时间,单位毫秒,zookeeper使用基本时间,服务器之间或客户端之间维持心跳时间的间隔,也就是每个tickTime时间就会发送一个心跳,时间单位为毫秒,它用于心跳机制,并且设置最小的session超时时间为两倍心跳时间(session最小超时时间是2*tickTime)
2.
3.2.initLimit=10 : LF初始化通信时限集群中的follower跟随者服务器Leader领导者服务器之间初始化连接时能容忍的最多心跳数
4.(tickTime数量),用它来跟限定集群中的zookeeper服务器连接到leader时限
5.
6.3.syncLimit=5 : LF同步通信时限集群中leader与follower之间最大响应时间单位,响应超过syncLimit*tickTime
7.4.dataDir 数据文件目录+数据持久化路径 保存zookeeper数据
8.5.clientProt 客户端 端口号 监听客户端连接端口
半数机制,集群中半数以上机器存活,集群可用,所以zookeeper适合安装奇数台服务器,zookeeper虽然在配置文件中并没有指定,但是zookeeper工作时,是有一个节点为leader,其他则为follower,leader是通过内部选举机制临时产生
持久(Persistent)客户端和服务端断开连接后,创建节点不删除,持久化目录节点,客户端与zookeeper断开连接后,该节点依旧存在,持久化顺序编号目录和节点,客户端与zookeeper断开连接后,该节点依旧存在,只是zookeeper给节点名称进行顺序编号,说明:创建znode时设置顺序标识,znode名称后会附加一个值,顺序号是一个单调递增的计数器,由父节点维护在分布式系统中,顺便号可以被用于为所以的事情进行全局排序,这样客户端可以通过顺序号推断事件顺序
短暂(Ephemeral)客户端和服务端断开连接后,创建节点自动删除
czxid-创建节点的事物zxid,每次修改zookeeper状态都会收到一个zxid形式的时间戳,也就是zookeeper事物的id号,事物id是zookeeper中所有修改总的次序,每个修改都有唯一的zxid,如zxid1小于zxid2,那么zxid1在zxid2之前发生
ctime-znode被创建的毫秒数(从1970年开始)
mzxid-znode最后更新的事物id
pZxid-znode最后修改的毫秒数(从1970年开始)
eversion-znode子节点变化号,znode子节点修改次数
dataversion-znode数据变化号
aclVersion-znode访问控制列表的变化号
ephemeralOwner-如果是临时节点,这个是znode拥有这的session id,如果不是临时节点则是0
dataLength-znode数据长度
numChildren-znode子节点数量
1.首先要有一个
main()客户端线程.
2.在main线程中创建zookeeper客户端,这时候就会创建两个线程,一个负责网络连接通信(connect),一个负责监听(listener).
3.通过connect线程将注册的监听事件发送给zookeeper服务端.
4.在zookeeper服务端注册监听器列表中进注册的监听事件添加到列表中.
5.zookeeper服务端监听到所有数据或路径变化,就会将这个消息发送给listener线程.
6.listener线程内部调用了process()方法
1.监听节点数据变化
get path[watch]
2.监听子节点增减变化ls path[watch]
1.#cd指令进入到zkData/目录下
2.[root@corehub zookeeper]# cd zkData/
3.#touch指令创建myid文件
4.[root@corehub zkData]# touch myid
5.#vim模式编辑此文件
6.[root@corehub zkData]# vim myid
7.#输入1,表示zookeeper服务器编号id为1,后两台服务器配置步骤如法炮制
8.1
9.~
10.esc退出编辑模式 输入:wq写入并退出
11.[root@corehub zkData]# vim myid
12.#输入2
13.2
14.~
15.esc退出编辑模式 输入:wq写入并退出
16.[root@corehub zkData]# vim myid
17.#输入3
18.3
19.~
20.esc退出编辑模式 输入:wq写入并退出
配置参数解读
server.A=B:C:D
A映射myid,代表第几号服务器
B映射服务器hostname
C服务器与集群中leader服务交换信息端口
D代表备选服务交换信息端口
1.[root@corehub conf]# vim zoo.cfg
2.
3.# The number of milliseconds of each tick
4.tickTime=2000
5.# The number of ticks that the initial
6.# synchronization phase can take
7.initLimit=10
8.# The number of ticks that can pass between
9.# sending a request and getting an acknowledgement
10.syncLimit=5
11.# the directory where the snapshot is stored.
12.# do not use /tmp for storage, /tmp here is just
13.# example sakes.
14.dataDir=/opt/devtool/zookeeper/zkData
15.# the port at which the clients will connect
16.clientPort=2181
17.# the maximum number of client connections.
18.# increase this if you need to handle more clients
19.#maxClientCnxns=60
20.################增加节点配置####################
21.#编辑完毕后,esc退出编辑模式 输入:wq写入并退出
22.server.1=corehub-001:2888:3888
23.server.2=corehub-002:2888:3888
24.server.3=corehub-003:2888:3888
25.#
26.# Be sure to read the maintenance section of the
27.# administrator guide before turning on autopurge.
28.#
29.# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
30.#
31.# The number of snapshots to retain in dataDir
32.#autopurge.snapRetainCount=3
33.# Purge task interval in hours
34.# Set to "0" to disable auto purge feature
35.#autopurge.purgeInterval=1
36.~
37.~
1.#在bin目录下执行并启动001号服务端
2.[root@corehub-001 zookeeper]# bin/zkServer.sh start
3.#查看001号服务端状态
4.[root@corehub-001 zookeeper]# bin/zkServer.sh status
5.
6.#在bin目录下执行并启动002号服务端
7.[root@corehub-002 zookeeper]# bin/zkServer.sh start
8.#查看002号服务端状态
9.[root@corehub-002 zookeeper]# bin/zkServer.sh status
10.
11.#在bin目录下执行并启动003号服务端
12.[root@corehub-003 zookeeper]# bin/zkServer.sh start
13.#查看003号服务端状态
14.[root@corehub-003 zookeeper]# bin/zkServer.sh status
help指令 显示所有操作命令
ls /查看当前znode中所包含的内容指令
ls2 /查看当前节点详细数据指令
create /znode "commit"创建两个普通节点
get /获得节点信息指令
create -e /创建短暂节点指令
💻 IntelliJ IDEA 全宇宙神器 构建maven project 💻
1.<?xml version="1.0" encoding="UTF-8"?>
2.<project xmlns="http://maven.apache.org/POM/4.0.0"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5. <modelVersion>4.0.0</modelVersion>
6. <groupId>com.geekparkhub</groupId>
7. <artifactId>ZookeeperTest</artifactId>
8. <version>1.0-SNAPSHOT</version>
9. <dependencies>
10. <!-- add junit单元测试 -->
11. <!-- https://mvnrepository.com/artifact/junit/junit -->
12. <dependency>
13. <groupId>junit</groupId>
14. <artifactId>junit</artifactId>
15. <version>RELEASE</version>
16. </dependency>
17. <!-- add log4j日志管理 -->
18. <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
19. <dependency>
20. <groupId>org.apache.logging.log4j</groupId>
21. <artifactId>log4j-core</artifactId>
22. <version>2.8.2</version>
23. </dependency>
24. <!-- add zookeeper -->
25. <!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
26. <dependency>
27. <groupId>org.apache.zookeeper</groupId>
28. <artifactId>zookeeper</artifactId>
29. <version>3.4.10</version>
30. </dependency>
31. </dependencies>
32.</project>
1.log4j.rootLogger=INFO, stdout
2.log4j.appender.stdout=org.apache.log4j.ConsoleAppender
3.log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
4.log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
5.log4j.appender.logfile=org.apache.log4j.FileAppender
6.log4j.appender.logfile.File=target/corehub.log
7.log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
8.log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
Start corehub-001号 zookeeper服务端 并查看本机IP地址Code Snippet | (corehub-001号 服务端)代码片段
1.##### bin/zkServer.sh start指令 启动zookeeper corehub-001号 服务端 #####
2.[root@corehub-001 zookeeper]# bin/zkServer.sh start
3.ZooKeeper JMX enabled by default
4.Using config: /opt/devtool/zookeeper/bin/../conf/zoo.cfg
5.Starting zookeeper ... already running as process 3548.
6.##### jps指令 查看zookeeper进程 #####
7.[root@corehub-001 zookeeper]# jps
8.3548 QuorumPeerMain
9.3710 Jps
10.##### ifconfig指令 查看本机IP地址 #####
11.[root@corehub-001 zookeeper]# ifconfig
12.eth0 Link encap:Ethernet HWaddr 00:0C:29:15:A8:CC
13. inet addr:192.168.177.128 Bcast:192.168.177.255 Mask:255.255.255.0
14. inet6 addr: fe80::20c:29ff:fe15:a8cc/64 Scope:Link
15. UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
16. RX packets:3966 errors:0 dropped:0 overruns:0 frame:0
17. TX packets:779 errors:0 dropped:0 overruns:0 carrier:0
18. collisions:0 txqueuelen:1000
19. RX bytes:276552 (270.0 KiB) TX bytes:64739 (63.2 KiB)
20. lo Link encap:Local Loopback
21. inet addr:127.0.0.1 Mask:255.0.0.0
22. inet6 addr: ::1/128 Scope:Host
23. UP LOOPBACK RUNNING MTU:65536 Metric:1
24. RX packets:10 errors:0 dropped:0 overruns:0 frame:0
25. TX packets:10 errors:0 dropped:0 overruns:0 carrier:0
26. collisions:0 txqueuelen:0
27. RX bytes:584 (584.0 b) TX bytes:584 (584.0 b)
28.[root@corehub-001 zookeeper]#
Start corehub-002号 zookeeper服务端 并查看本机IP地址Code Snippet | (corehub-002号 服务端)代码片段
1.##### bin/zkServer.sh start指令 启动zookeeper corehub-002号 服务端 #####
2.[root@corehub-002 zookeeper]# bin/zkServer.sh start
3.ZooKeeper JMX enabled by default
4.Using config: /opt/devtool/zookeeper/bin/../conf/zoo.cfg
5.Starting zookeeper ... already running as process 3194.
6.##### jps指令 查看zookeeper进程 #####
7.[root@corehub-002 zookeeper]# jps
8.3376 Jps
9.3194 QuorumPeerMain
10.##### ifconfig指令 查看本机IP地址 #####
11.[root@corehub-002 zookeeper]# ifconfig
12.eth1 Link encap:Ethernet HWaddr 00:0C:29:98:7B:7D
13. inet addr:192.168.177.129 Bcast:192.168.177.255 Mask:255.255.255.0
14. inet6 addr: fe80::20c:29ff:fe98:7b7d/64 Scope:Link
15. UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
16. RX packets:2103 errors:0 dropped:0 overruns:0 frame:0
17. TX packets:654 errors:0 dropped:0 overruns:0 carrier:0
18. collisions:0 txqueuelen:1000
19. RX bytes:157031 (153.3 KiB) TX bytes:52690 (51.4 KiB)
20. lo Link encap:Local Loopback
21. inet addr:127.0.0.1 Mask:255.0.0.0
22. inet6 addr: ::1/128 Scope:Host
23. UP LOOPBACK RUNNING MTU:65536 Metric:1
24. RX packets:10 errors:0 dropped:0 overruns:0 frame:0
25. TX packets:10 errors:0 dropped:0 overruns:0 carrier:0
26. collisions:0 txqueuelen:0
27. RX bytes:584 (584.0 b) TX bytes:584 (584.0 b)
28.[root@corehub-002 zookeeper]#
Start corehub-003号 zookeeper服务端 并查看本机IP地址Code Snippet | (corehub-003号 服务端)代码片段
1.##### bin/zkServer.sh start指令 启动zookeeper corehub-003号 服务端 #####
2.[root@corehub-003 zookeeper]# bin/zkServer.sh start
3.ZooKeeper JMX enabled by default
4.Using config: /opt/devtool/zookeeper/bin/../conf/zoo.cfg
5.Starting zookeeper ... already running as process 3242.
6.##### jps指令 查看zookeeper进程 #####
7.[root@corehub-003 zookeeper]# jps
8.3505 Jps
9.3242 QuorumPeerMain
10.##### ifconfig指令 查看本机IP地址 #####
11.[root@corehub-003 zookeeper]# ifconfig
12.eth1 Link encap:Ethernet HWaddr 00:0C:29:12:C5:F0
13. inet addr:192.168.177.130 Bcast:192.168.177.255 Mask:255.255.255.0
14. inet6 addr: fe80::20c:29ff:fe12:c5f0/64 Scope:Link
15. UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
16. RX packets:2078 errors:0 dropped:0 overruns:0 frame:0
17. TX packets:633 errors:0 dropped:0 overruns:0 carrier:0
18. collisions:0 txqueuelen:1000
19. RX bytes:156371 (152.7 KiB) TX bytes:51085 (49.8 KiB)
20. lo Link encap:Local Loopback
21. inet addr:127.0.0.1 Mask:255.0.0.0
22. inet6 addr: ::1/128 Scope:Host
23. UP LOOPBACK RUNNING MTU:65536 Metric:1
24. RX packets:10 errors:0 dropped:0 overruns:0 frame:0
25. TX packets:10 errors:0 dropped:0 overruns:0 carrier:0
26. collisions:0 txqueuelen:0
27. RX bytes:584 (584.0 b) TX bytes:584 (584.0 b)
28.[root@corehub-003 zookeeper]#
为了大家在第四步避免入坑,以当前三台虚拟机为例,需在windows系统中映射对应IP地址与主机名⚠️⚠️1.#### Copy Addr ####
2.C:\Windows\System32\drivers\etc
3.#### 使用编辑器打开hosts文件 ####
4.#### 新增IP地址和主机名 ####
5.192.168.177.128 corehub-001
6.192.168.177.129 corehub-002
7.192.168.177.130 corehub-003
1.package com.geekparkhub.zookeeper;
2.
3.import org.apache.log4j.Logger;
4.import org.apache.zookeeper.*;
5.import org.junit.Test;
6.import java.io.IOException;
7.
8./**
9. * GeekParkHub | 极客国际公园
10. * GeekDeveloper : JEEP-711
11. * Website | https://www.geekparkhub.com/
12. * Description | Open开放 · Creation创想 | OpenSource开放成就梦想 GeekParkHub共建前所未见
13. *
14. * Zookeeper测试类
15. */
16.
17.public class ZookeeperTest {
18.
19. /**
20. * Statement Logger
21. */
22. private static org.apache.log4j.Logger log = Logger.getLogger(ZookeeperTest.class);
23.
24. /**
25. * 服务端主机名称:Zookeeper客户端 端口号
26. * Server HostName : Zookeeper Client port
27. */
28. private String connectString="corehub-001:2181,corehub-002:2181,corehub-003:2181";
29.
30. /**
31. * 设置会话超时间 5000毫秒 = 5秒
32. * Set session timeout 5000 milliseconds = 5 seconds
33. */
34. private int sessionTimeout = 5000;
35.
36. /**
37. * 全局ZooKeeper客户端
38. * Global Zoo Keeper client
39. */
40. private ZooKeeper zkClient;
41.
42. /**
43. * 初始化方法
44. * Initialization Method
45. */
46. @Test
47. public void init() throws IOException {
48. zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
49. public void process(WatchedEvent watchedEvent) {
50. }
51. });
52. }
53.}
Error contacting service. It is probably not running.❌❌corehub-001号 | 进程正常开启,但服务没有运行
1.[root@corehub-001 zookeeper]# bin/zkServer.sh status
2.ZooKeeper JMX enabled by default
3.Using config: /opt/devtool/zookeeper/bin/../conf/zoo.cfg
4.Error contacting service. It is probably not running.
5.[root@corehub-001 zookeeper]# jps
6.4293 Jps
7.3548 QuorumPeerMain
corehub-002号 | 进程正常开启,但服务没有运行
1.[root@corehub-002 zookeeper]# bin/zkServer.sh status
2.ZooKeeper JMX enabled by default
3.Using config: /opt/devtool/zookeeper/bin/../conf/zoo.cfg
4.Error contacting service. It is probably not running.
5.[root@corehub-002 zookeeper]# jps
6.3809 Jps
7.3194 QuorumPeerMain
corehub-003号 | 进程正常开启,但服务没有运行
1.[root@corehub-003 zookeeper]# bin/zkServer.sh status
2.ZooKeeper JMX enabled by default
3.Using config: /opt/devtool/zookeeper/bin/../conf/zoo.cfg
4.Error contacting service. It is probably not running.
5.[root@corehub-003 zookeeper]# jps
6.3956 Jps
7.3242 QuorumPeerMain
8.[root@corehub-003 zookeeper]#
解决当前问题的前提,确保myid中的ID号正确无误
原因是防火墙没有关闭,在关闭防火墙前提下,先需要依次停止01,02,03号zookeeper服务端
1.[root@corehub-001 zookeeper]# bin/zkServer.sh stop
2.ZooKeeper JMX enabled by default
3.Using config: /opt/devtool/zookeeper/bin/../conf/zoo.cfg
4.Stopping zookeeper ... STOPPED
1.[root@corehub-002 zookeeper]# bin/zkServer.sh stop
2.ZooKeeper JMX enabled by default
3.Using config: /opt/devtool/zookeeper/bin/../conf/zoo.cfg
4.Stopping zookeeper ... STOPPED
1.[root@corehub-003 zookeeper]# bin/zkServer.sh stop
2.ZooKeeper JMX enabled by default
3.Using config: /opt/devtool/zookeeper/bin/../conf/zoo.cfg
4.Stopping zookeeper ... STOPPED
最后依次关闭01,02,03号防火墙,并依次重新启动01,02,03号zookeeper服务端
依次启动和关闭的步骤就在此省略了,步骤按照案例以此类推即可
1.[root@corehub-001 zookeeper]# service iptables stop
2.iptables: Setting chains to policy ACCEPT: filter [ OK ]
3.iptables: Flushing firewall rules: [ OK ]
4.iptables: Unloading modules: [ OK ]
此时此刻我们看到了令人满意的结果😄😄
通过zookeeper 选举机制,我们可看出在集群中只要半数以上机器存活,就可以推选出Leader最为集群中的领导者
很显然corehub-002号服务作为Leader领导者,而剩下的corehub-001&corehub-003将作为follower跟随者
1.[root@corehub-001 zookeeper]# bin/zkServer.sh status
2.ZooKeeper JMX enabled by default
3.Using config: /opt/devtool/zookeeper/bin/../conf/zoo.cfg
4.Mode: follower
5.[root@corehub-001 zookeeper]#
1.[root@corehub-002 zookeeper]# bin/zkServer.sh status
2.ZooKeeper JMX enabled by default
3.Using config: /opt/devtool/zookeeper/bin/../conf/zoo.cfg
4.Mode: leader
5.[root@corehub-002 zookeeper]#
1.[root@corehub-003 zookeeper]# bin/zkServer.sh status
2.ZooKeeper JMX enabled by default
3.Using config: /opt/devtool/zookeeper/bin/../conf/zoo.cfg
4.Mode: follower
5.[root@corehub-003 zookeeper]#
1.package com.geekparkhub.zookeeper;
2.
3.import org.apache.log4j.Logger;
4.import org.apache.zookeeper.*;
5.import org.junit.Before;
6.import org.junit.Test;
7.import java.io.IOException;
8.
9./**
10. * GeekParkHub | 极客国际公园
11. * GeekDeveloper : JEEP-711
12. * Website | https://www.geekparkhub.com/
13. * Description | Open开放 · Creation创想 | OpenSource开放成就梦想 GeekParkHub共建前所未见
14. *
15. * Zookeeper测试类
16. */
17.
18.public class ZookeeperTest {
19.
20. /**
21. * Statement Logger
22. */
23. private static org.apache.log4j.Logger log = Logger.getLogger(ZookeeperTest.class);
24.
25. /**
26. * 服务端主机名称:Zookeeper客户端 端口号
27. * Server HostName : Zookeeper Client port
28. */
29. private String connectString="corehub-001:2181,corehub-002:2181,corehub-003:2181";
30.
31. /**
32. * 设置会话超时间 5000毫秒 = 5秒
33. * Set session timeout 5000 milliseconds = 5 seconds
34. */
35. private int sessionTimeout = 5000;
36.
37. /**
38. * 全局ZooKeeper客户端
39. * Global Zoo Keeper client
40. */
41. private ZooKeeper zkClient;
42.
43.
44. /**
45. * 初始化方法
46. * Initialization Method
47. */
48. @Before
49. public void init() throws IOException {
50. zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
51. public void process(WatchedEvent watchedEvent) {
52. }
53. });
54. }
55.
56. /**
57. * 创建子节点方法
58. * Create child node method
59. */
60. @Test
61. public void createNode() throws KeeperException, InterruptedException {
62. /**
63. * 引用客户端对象 调用create方法
64. *
65. * create(path,data,acl,createMode);
66. * path 表示节点路径,在根目录下创建/geekparkhub路径
67. * data 表示节点内容,内容不支持String类型字符串,应转型为字节类型
68. * acl 表示访问权限控制,在ZooDefs.Ids中定义了接口变量,OPEN_ACL_UNSAFE不需要权限即可访问
69. * createMode 表示节点储存数据类型 / 持久(Persistent) & 短暂(Ephemeral)
70. */
71. String path = zkClient.create("/geekparkhub","Open开放 · Creation创想 | OpenSource开放成就梦想 GeekParkHub共建前所未见".getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
72. log.info("Info : "+path);
73. }
74.}
1.[root@corehub-001 zookeeper]# bin/zkCli.sh
2.Connecting to localhost:2181
3.2019-01-22 01:17:08,677 [myid:] - INFO [main:Environment@100] - Client environment:user.name=root
4.2019-01-22 01:17:08,677 [myid:] - INFO [main:Environment@100] - Client environment:user.home=/root
5.JLine support is enabled
6.2019-01-22 01:17:09,001 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@876] - Socket connection established to localhost/127.0.0.1:2181, initiating session
7.2019-01-22 01:17:09,028 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@1299] - Session establishment complete on server localhost/127.0.0.1:2181, sessionid = 0x16871456f950001, negotiated timeout = 30000
8.WATCHER::
get / 指令,查询当前客户端向服务端写入的数据1.[zk: localhost:2181(CONNECTED) 0] get /geekparkhub
2.Open开放 · Creation创想 | OpenSource开放成就梦想 GeekParkHub共建前所未见
3.cZxid = 0x100000002
4.ctime = Tue Jan 22 00:38:11 CST 2019
5.mZxid = 0x100000002
6.mtime = Tue Jan 22 00:38:11 CST 2019
7.pZxid = 0x100000002
8.cversion = 0
9.dataVersion = 0
10.aclVersion = 0
11.ephemeralOwner = 0x0
12.dataLength = 89
13.numChildren = 0
14.[zk: localhost:2181(CONNECTED) 1]
1.package com.geekparkhub.zookeeper;
2.
3.import org.apache.log4j.Logger;
4.import org.apache.zookeeper.*;
5.import org.junit.Before;
6.import org.junit.Test;
7.import java.io.IOException;
8.import java.util.List;
9.
10./**
11. * GeekParkHub | 极客国际公园
12. * GeekDeveloper : JEEP-711
13. * Website | https://www.geekparkhub.com/
14. * Description | Open开放 · Creation创想 | OpenSource开放成就梦想 GeekParkHub共建前所未见
15. *
16. * Zookeeper测试类
17. */
18.
19.public class ZookeeperTest {
20.
21. /**
22. * Statement Logger
23. */
24. private static org.apache.log4j.Logger log = Logger.getLogger(ZookeeperTest.class);
25.
26. /**
27. * 服务端主机名称:Zookeeper客户端 端口号
28. * Server HostName : Zookeeper Client port
29. */
30. private String connectString="corehub-001:2181,corehub-002:2181,corehub-003:2181";
31.
32. /**
33. * 设置会话超时间 5000毫秒 = 5秒
34. * Set session timeout 5000 milliseconds = 5 seconds
35. */
36. private int sessionTimeout = 5000;
37.
38. /**
39. * 全局ZooKeeper客户端
40. * Global Zoo Keeper client
41. */
42. private ZooKeeper zkClient;
43.
44.
45. /**
46. * 实时监听器 初始化方法
47. * Initialization Method
48. */
49. @Before
50. public void init() throws IOException {
51. zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
52. public void process(WatchedEvent watchedEvent) {
53. /**
54. * 引用客户端对象 调用getChildren方法
55. * getChildren(path,watcher);
56. * path 获取根路径下,所有的子节点
57. * watcher 是否监听 false / true
58. *
59. */
60. log.info("--------- Start ---------");
61. List<String> children = null;
62. try {
63. children = zkClient.getChildren("/",true);
64. /**
65. * for循环 实时监听 遍历输出节点变化
66. */
67. for (String child : children){
68. log.info("Znode : "+child);
69. }
70. log.info("--------- End ---------");
71. } catch (KeeperException e) {
72. e.printStackTrace();
73. } catch (InterruptedException e) {
74. e.printStackTrace();
75. }
76. }
77. });
78. }
79.
80. /**
81. * 创建子节点方法
82. * Create child node method
83. */
84. @Test
85. public void createNode() throws KeeperException, InterruptedException {
86.
87. /**
88. * 引用客户端对象 调用create方法
89. *
90. * create(path,data,acl,createMode);
91. * path 表示节点路径,在根目录下创建/geekparkhub路径
92. * data 表示节点内容,内容不支持String类型字符串,应转型为字节类型
93. * acl 表示访问权限控制,在ZooDefs.Ids中定义了接口变量,OPEN_ACL_UNSAFE不需要权限即可访问
94. * createMode 表示节点储存数据类型 / 持久(Persistent) & 短暂(Ephemeral)
95. */
96.
97. String path = zkClient.create("/geekparkhub","Open开放 · Creation创想 | OpenSource开放成就梦想 GeekParkHub共建前所未见".getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
98. log.info("Info : "+path);
99. }
100.
101. /**
102. * 获取子节点并监听节点变化
103. */
104. @Test
105. public void getDataWatcher() throws KeeperException, InterruptedException {
106. /**
107. * 为避免循环结束,无法实时监听,调用sleep方法
108. */
109. Thread.sleep(Long.MAX_VALUE);
110. }
111.}
create / 指令执行创建节点指令1.[zk: localhost:2181(CONNECTED) 1] ls /
2.[zookeeper, geekparkhub]
3.[zk: localhost:2181(CONNECTED) 2] create /jeep-711 "GeekDeveloper"
4.Created /jeep-711
5.[zk: localhost:2181(CONNECTED) 3] create /geek "geek"
6.Created /geek
7.[zk: localhost:2181(CONNECTED) 4] create /geeklab "geeklab"
8.Created /geeklab
9.[zk: localhost:2181(CONNECTED) 5] create /geekpark "geekpark"
10.Created /geekpark
11.[zk: localhost:2181(CONNECTED) 6] create /geekparks "geekparks"
12.Created /geekparks
13.[zk: localhost:2181(CONNECTED) 7] ls /
14.[zookeeper, geekparkhub, geek, geeklab, geekparks, jeep-711, geekpark]
15.[zk: localhost:2181(CONNECTED) 8]
1.package com.geekparkhub.zookeeper;
2.
3.import org.apache.log4j.Logger;
4.import org.apache.zookeeper.*;
5.import org.apache.zookeeper.data.Stat;
6.import org.junit.Before;
7.import org.junit.Test;
8.import java.io.IOException;
9.import java.util.List;
10.
11./**
12. * GeekParkHub | 极客国际公园
13. * GeekDeveloper : JEEP-711
14. * Website | https://www.geekparkhub.com/
15. * Description | Open开放 · Creation创想 | OpenSource开放成就梦想 GeekParkHub共建前所未见
16. *
17. * Zookeeper测试类
18. */
19.
20.public class ZookeeperTest {
21.
22. /**
23. * Statement Logger
24. */
25. private static org.apache.log4j.Logger log = Logger.getLogger(ZookeeperTest.class);
26.
27. /**
28. * 服务端主机名称:Zookeeper客户端 端口号
29. * Server HostName : Zookeeper Client port
30. */
31. private String connectString="corehub-001:2181,corehub-002:2181,corehub-003:2181";
32.
33. /**
34. * 设置会话超时间 5000毫秒 = 5秒
35. * Set session timeout 5000 milliseconds = 5 seconds
36. */
37. private int sessionTimeout = 5000;
38.
39. /**
40. * 全局ZooKeeper客户端
41. * Global Zoo Keeper client
42. */
43. private ZooKeeper zkClient;
44.
45. /**
46. * 实时监听器 初始化方法
47. * Initialization Method
48. */
49. @Before
50. public void init() throws IOException {
51. zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
52. public void process(WatchedEvent watchedEvent) {
53.
54. /**
55. * 引用客户端对象 调用getChildren方法
56. * getChildren(path,watcher);
57. * path 获取根路径下,所有的子节点
58. * watcher 是否监听 false / true
59. *
60. */
61.// log.info("--------- Start ---------");
62.// List<String> children = null;
63.// try {
64.// children = zkClient.getChildren("/",true);
65.// /**
66.// * for循环 实时监听 遍历输出节点变化
67.// */
68.// for (String child : children){
69.// log.info("Znode : "+child);
70.// }
71.// log.info("--------- End ---------");
72.// } catch (KeeperException e) {
73.// e.printStackTrace();
74.// } catch (InterruptedException e) {
75.// e.printStackTrace();
76.// }
77. }
78. }
79. );
80. }
81.
82. /**
83. * 创建子节点方法
84. * Create child node method
85. */
86. @Test
87. public void createNode() throws KeeperException, InterruptedException {
88.
89. /**
90. * 引用客户端对象 调用create方法
91. *
92. * create(path,data,acl,createMode);
93. * path 表示节点路径,在根目录下创建/geekparkhub路径
94. * data 表示节点内容,内容不支持String类型字符串,应转型为字节类型
95. * acl 表示访问权限控制,在ZooDefs.Ids中定义了接口变量,OPEN_ACL_UNSAFE不需要权限即可访问
96. * createMode 表示节点储存数据类型 / 持久(Persistent) & 短暂(Ephemeral)
97. */
98.
99. String path = zkClient.create("/geekparkhub","Open开放 · Creation创想 | OpenSource开放成就梦想 GeekParkHub共建前所未见".getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
100. log.info("Info : "+path);
101. }
102.
103. /**
104. * 获取子节点并监听节点变化
105. */
106. @Test
107. public void getDataWatcher() throws KeeperException, InterruptedException {
108. /**
109. * 为避免循环结束,无法实时监听,调用sleep方法
110. */
111.// Thread.sleep(Long.MAX_VALUE);
112. }
113.
114. /**
115. * 判断Zonde是否存在
116. */
117. @Test
118. public void exist() throws KeeperException, InterruptedException {
119.
120. /**
121. * 引用客户端对象 调用exists方法
122. * exists(path,watcher); 判断此节点是否有数据
123. * path 获取此路径下,所有数据
124. * watcher 是否监听 false / true
125. *
126. * 判断 /geek节点中,是否有数据
127. */
128.
129. Stat exists = zkClient.exists("/geek",true);
130. log.info("该节点存在且有数据 : "+exists == null ? "该节点不存在!":"该节点存在且有数据");
131. }
132.}
在分布式系统中,主节点可以有多台,可以动态上下线,任意一台客户端都有可以实时感知到主节点服务器上下线
1.create /servers "server"
2.Created /servers
3.[zk: localhost:2181(CONNECTED) 1] ls /
4.[servers, zookeeper]
5.[zk: localhost:2181(CONNECTED) 2]
1.package com.geekparkhub.zookeeper;
2.
3.import org.apache.log4j.Logger;
4.import org.apache.zookeeper.*;
5.import java.io.IOException;
6.
7./**
8. * GeekParkHub | 极客国际公园
9. * GeekDeveloper : JEEP-711
10. * Website | https://www.geekparkhub.com/
11. * Description | Open开放 · Creation创想 | OpenSource开放成就梦想 GeekParkHub共建前所未见
12. * <p>
13. * 分发服务端 Class
14. */
15.
16.public class DistributeServer {
17.
18. /**
19. * Statement Logger
20. */
21. private static org.apache.log4j.Logger log = Logger.getLogger(DistributeServer.class);
22.
23. /**
24. * 服务端主机名称:Zookeeper客户端 端口号
25. * Server HostName : Zookeeper Client port
26. */
27. private String connectString = "corehub-001:2181,corehub-002:2181,corehub-003:2181";
28.
29. /**
30. * 设置会话超时间 5000毫秒 = 5秒
31. * Set session timeout 5000 milliseconds = 5 seconds
32. */
33. private int sessionTimeout = 5000;
34.
35. /**
36. * 全局ZooKeeper客户端
37. * Global Zoo Keeper client
38. */
39. private ZooKeeper zkClient;
40.
41. public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
42.
43. /**
44. * 实例化 DistributeServer
45. */
46. DistributeServer server = new DistributeServer();
47.
48. /**
49. * 连接 Zookeeper服务端集群
50. * 调用getConnect()方法,建立网络连接
51. */
52. server.getConnect();
53.
54. /**
55. * 向Zookeeper服务器 注册节点
56. * 调用regist()方法,
57. */
58. server.regist(args[0]);
59.
60. /**
61. * 实现 业务逻辑
62. */
63. server.business();
64.
65. }
66.
67. /**
68. * 定义 建立网络连接方法
69. */
70. private void getConnect() throws IOException {
71. zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
72. public void process(WatchedEvent watchedEvent) {
73. }
74. });
75. }
76.
77. /**
78. * 定义 注册方法
79. * CreateMode.EPHEMERAL_SEQUENTIAL 表示短暂并带序号的数据存储,实现节点上下线
80. * String hostname,当前属性需要动态获取主机名称,客户端每注册一次,就更新一次记录
81. */
82. private void regist(String hostname) throws KeeperException, InterruptedException {
83. String path = zkClient.create("/servers/server", hostname.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
84. log.info("⬆️" + hostname + "is Online!");
85. }
86.
87. /**
88. * 业务逻辑
89. */
90. private void business() throws InterruptedException {
91. /**
92. * 让程序在睡一会
93. */
94. Thread.sleep(Long.MAX_VALUE);
95. }
96.}
1.package com.geekparkhub.zookeeper;
2.
3.import org.apache.log4j.Logger;
4.import org.apache.zookeeper.KeeperException;
5.import org.apache.zookeeper.WatchedEvent;
6.import org.apache.zookeeper.Watcher;
7.import org.apache.zookeeper.ZooKeeper;
8.import java.io.IOException;
9.import java.util.ArrayList;
10.import java.util.List;
11.
12./**
13. * GeekParkHub | 极客国际公园
14. * GeekDeveloper : JEEP-711
15. * Website | https://www.geekparkhub.com/
16. * Description | Open开放 · Creation创想 | OpenSource开放成就梦想 GeekParkHub共建前所未见
17. * <p>
18. * 分发客户端 Class
19. */
20.
21.public class DistributeClient {
22.
23. /**
24. * Statement Logger
25. */
26. private static org.apache.log4j.Logger log = Logger.getLogger(DistributeClient.class);
27.
28. /**
29. * 服务端主机名称:Zookeeper客户端 端口号
30. * Server HostName : Zookeeper Client port
31. */
32. private String connectString = "corehub-001:2181,corehub-002:2181,corehub-003:2181";
33.
34. /**
35. * 设置会话超时间 5000毫秒 = 5秒
36. * Set session timeout 5000 milliseconds = 5 seconds
37. */
38. private int sessionTimeout = 5000;
39.
40. /**
41. * 全局ZooKeeper客户端
42. * Global Zoo Keeper client
43. */
44. private ZooKeeper zkClient;
45.
46. public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
47.
48. /**
49. * 实例化 DistributeClient
50. */
51. DistributeClient client = new DistributeClient();
52.
53. /**
54. * 获取 Zookeeper服务端集群连接
55. * 调用getConnect()方法,建立网络连接
56. */
57. client.getConnect();
58.
59. /**
60. * 注册监听节点
61. */
62. client.getMonitor();
63.
64. /**
65. * 业务逻辑
66. */
67. client.business();
68. }
69.
70. /**
71. * 定义 建立网络连接方法
72. */
73. private void getConnect() throws IOException {
74. zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
75. /**
76. * 无限实时监听 getMonitor方法
77. * @param watchedEvent
78. */
79. public void process(WatchedEvent watchedEvent) {
80. try {
81. getMonitor();
82. } catch (KeeperException e) {
83. e.printStackTrace();
84. } catch (InterruptedException e) {
85. e.printStackTrace();
86. }
87. }
88. });
89. }
90.
91. /**
92. * 定义 注册监听节点
93. */
94. private void getMonitor() throws KeeperException, InterruptedException {
95.
96. List<String> children = zkClient.getChildren("/servers", true);
97.
98. /**
99. * 用于存储服务器节点主机名称集合
100. */
101. ArrayList<String> hosts = new ArrayList<String>();
102.
103. for (String child : children) {
104. // 获取当前节点下的所以数据源
105. byte[] data = zkClient.getData("/servers/" + child, false, null);
106. hosts.add(new String(data));
107. }
108. // 将所有 在线主机名称 打印结果集
109. log.info("==♨️== " + hosts + " ==♨️==");
110. }
111.
112. /**
113. * 定义 业务逻辑
114. */
115. private void business() throws InterruptedException {
116. /**
117. * 让程序在睡一会
118. */
119. Thread.sleep(Long.MAX_VALUE);
120. }
121.}
Blog内容大多是手敲,所以难免会有笔误,你可以帮我找错别字。
很多知识点我可能没有涉及到,所以你可以对其他知识点进行补充。
现有的知识点难免存在不完善或者错误,所以你可以对已有知识点的修改/补充。
💡欢迎贡献各领域开源野生Blog&笔记&文章&片段&分享&创想&OpenSource Project&Code&Code Review
🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈 issues: geekparkhub.github.io/issues 🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈🙈
FaceBook:JEEP SevenEleven
Twitter:@JEEP7ll
Sina Weibo: @JEEP-711
GeekParkHub GithubHome:https://github.com/geekparkhub
GeekParkHub GiteeHome:https://gitee.com/geekparkhub
Blog GardenHome:http://www.cnblogs.com/JEEP711/
W3C/BlogHome:https://www.w3cschool.cn/jeep711blog/
CSDN/BlogHome:http://blog.csdn.net/jeep911
51CTO/BlogHome:http://jeep711.blog.51cto.com/
Email:jeep711.home.@gmail.com—— jeep-711@outlook.com —— geekparkhub@outlook.com
致谢:捐助时请备注 UserName
| ID | UserName | Donation | Money | Consume |
| 1 | Object | WeChatPay | 5RMB | 一杯可乐 |
| 2 | 泰迪熊看月亮 | AliPay | 20RMB | 一杯咖啡 |
| 3 | 修仙道长 | WeChatPay | 10RMB | 两杯可乐 |